package com.xgk.boot.module.core.util.price;

import com.xgk.boot.framework.common.constant.ErrorCodeConstants;
import com.xgk.boot.framework.common.exception.util.ServiceExceptionUtil;
import com.xgk.boot.framework.common.util.json.JsonUtils;
import com.xgk.boot.module.core.controller.admin.price.vo.PriceRuleVO;
import com.xgk.boot.module.core.dal.dto.SegmentPriceRuleDto;
import com.xgk.boot.module.core.enums.biz.CalcTypeEnum;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Comparator;
import java.util.List;

public class PriceCalcUtil {

    public static BigDecimal calculatePriceByRule(PriceRuleVO ruleVO, BigDecimal price) {
        CalcTypeEnum ruleType = CalcTypeEnum.valueOf(ruleVO.getCalculationRule());
        BigDecimal ruleValue = ruleVO.getRuleValue();
        if (ruleType == null) {
            return price;
        }
        switch (ruleType) {
            case Fixed_Price:
                //固定值
                return ruleValue;
            case Floating_Rate:
                //上浮率
                return price.multiply(ruleValue)
                        .setScale(2, RoundingMode.HALF_UP);
            case Fixed_Additional:
                //附加值
                return price.add(ruleValue);
            case Segmented:
                //分段计费
                return calculatePriceBySegmentRule(ruleVO, price);
            default:
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.COMMON_NOT_SUPPORTED, ruleType.name());
        }
    }

    private static BigDecimal calculatePriceBySegmentRule(PriceRuleVO ruleVO, BigDecimal price){
        String ruleExtendValue = ruleVO.getRuleExtendValue();
        List<SegmentPriceRuleDto>  segmentPriceRuleDtos = JsonUtils.parseArray(ruleExtendValue, SegmentPriceRuleDto.class);
        segmentPriceRuleDtos.sort(Comparator.comparing(
                SegmentPriceRuleDto::getRangeBegin,
                Comparator.nullsFirst(BigDecimal::compareTo)
        ));

        BigDecimal totalPrice = BigDecimal.ZERO;
        for (SegmentPriceRuleDto segment : segmentPriceRuleDtos) {
            if(segment.getRangeEnd() !=null){
                if (price.compareTo(segment.getRangeBegin()) >= 0 && price.compareTo(segment.getRangeEnd()) < 0) {
                    switch (segment.getCalculationRule()) {
                        case "rate":
                            totalPrice = price.multiply(segment.getRuleValue())
                                    .setScale(2, RoundingMode.HALF_UP);
                            break;
                        case "add":
                            totalPrice = price.add(segment.getRuleValue());
                            break;
                        case "fix":
                            totalPrice = segment.getRuleValue();
                            break;
                        default:
                            throw ServiceExceptionUtil.exception(ErrorCodeConstants.COMMON_NOT_SUPPORTED, segment.getCalculationRule());
                    }
                    break; // 找到匹配的分段后退出循环
                }
            }else {
                if (price.compareTo(segment.getRangeBegin()) >= 0 ) {
                    switch (segment.getCalculationRule()) {
                        case "rate":
                            totalPrice = price.multiply(segment.getRuleValue())
                                    .setScale(2, RoundingMode.HALF_UP);
                            break;
                        case "add":
                            totalPrice = price.add(segment.getRuleValue());
                            break;
                        case "fix":
                            totalPrice = segment.getRuleValue();
                            break;
                        default:
                            throw ServiceExceptionUtil.exception(ErrorCodeConstants.COMMON_NOT_SUPPORTED, segment.getCalculationRule());
                    }
                    break; // 找到匹配的分段后退出循环
                }
            }

        }
        return totalPrice;
    }


    public static BigDecimal calculatePriceAddChargeByRule(PriceRuleVO ruleVO, BigDecimal price) {
        CalcTypeEnum ruleType = CalcTypeEnum.valueOf(ruleVO.getCalculationRule());
        BigDecimal ruleValue = ruleVO.getRuleValue();
        if (ruleType == null) {
            return price;
        }
        switch (ruleType) {
            case Fixed_Price:
                //固定值
                return price.subtract(ruleValue);
            case Floating_Rate:
                //上浮率
                return price.multiply(ruleValue)
                        .setScale(2, RoundingMode.HALF_UP).subtract(price);
            case Fixed_Additional:
                //附加值
                return ruleValue;
            case Segmented:
                //分段计费
                return calculatePriceAddBySegmentRule(ruleVO, price);
            default:
                throw ServiceExceptionUtil.exception(ErrorCodeConstants.COMMON_NOT_SUPPORTED, ruleType.name());
        }
    }


    private static BigDecimal calculatePriceAddBySegmentRule(PriceRuleVO ruleVO, BigDecimal price){
        String ruleExtendValue = ruleVO.getRuleExtendValue();
        List<SegmentPriceRuleDto>  segmentPriceRuleDtos = JsonUtils.parseArray(ruleExtendValue, SegmentPriceRuleDto.class);
        segmentPriceRuleDtos.sort(Comparator.comparing(
                SegmentPriceRuleDto::getRangeBegin,
                Comparator.nullsFirst(BigDecimal::compareTo)
        ));

        BigDecimal totalPrice = BigDecimal.ZERO;
        for (SegmentPriceRuleDto segment : segmentPriceRuleDtos) {
            if(segment.getRangeEnd() !=null){
                if (price.compareTo(segment.getRangeBegin()) >= 0 && price.compareTo(segment.getRangeEnd()) < 0) {
                    switch (segment.getCalculationRule()) {
                        case "rate":
                            totalPrice = price.multiply(segment.getRuleValue())
                                    .setScale(2, RoundingMode.HALF_UP).subtract(price);
                            break;
                        case "add":
                            totalPrice = segment.getRuleValue();
                            break;
                        case "fix":
                            totalPrice = price.subtract(segment.getRuleValue());
                            break;
                        default:
                            throw ServiceExceptionUtil.exception(ErrorCodeConstants.COMMON_NOT_SUPPORTED, segment.getCalculationRule());
                    }
                    break; // 找到匹配的分段后退出循环
                }
            }else {
                if (price.compareTo(segment.getRangeBegin()) >= 0 ) {
                    switch (segment.getCalculationRule()) {
                        case "rate":
                            totalPrice = price.multiply(segment.getRuleValue())
                                    .setScale(2, RoundingMode.HALF_UP).subtract(price);
                            break;
                        case "add":
                            totalPrice = segment.getRuleValue();
                            break;
                        case "fix":
                            totalPrice = price.subtract(segment.getRuleValue());
                            break;
                        default:
                            throw ServiceExceptionUtil.exception(ErrorCodeConstants.COMMON_NOT_SUPPORTED, segment.getCalculationRule());
                    }
                    break; // 找到匹配的分段后退出循环
                }
            }

        }
        return totalPrice;
    }

    public static void main(String[] args) {
        BigDecimal price = new BigDecimal(100);
        BigDecimal ruleValue = new BigDecimal(1.2);
        BigDecimal subtract = price.multiply(ruleValue)
                .setScale(2, RoundingMode.HALF_UP).subtract(price);
        System.out.println(subtract);
    }


}
